package com.onlocation.db;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import com.onlocation.objects.Location;
import com.onlocation.util.CoordinateUtil;
import com.onlocation.util.StringUtil;
import com.onlocation.util.VolumeUtil;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Author: Steve Carrell
 * Date: 5/10/12
 */
public class DatabaseHelper extends SQLiteOpenHelper {
    private static DatabaseHelper instance = null;

    private static final int DATABASE_VERSION = 5;
    private static final String TABLE_NAME = "LOCATIONS";
    private static final String DEFAULT_KEY = "Default";
    
    private static final String CREATE_TABLE_SQL =
            "CREATE TABLE " + TABLE_NAME + " (" +
            "NAME TEXT PRIMARY KEY NOT NULL, " +
            "LONGITUDE TEXT NOT NULL, " +
            "LATITUDE TEXT NOT NULL, " +
            "RADIUS TEXT NOT NULL, " +
            "VOLUME INTEGER NOT NULL, " +
            "VIBRATE INTEGER NOT NULL" +
            "); ";
    
    private static final String GET_LOCATIONS_SQL =
            "SELECT NAME FROM " + TABLE_NAME + ";";
    
    private static final String GET_LOCATION_DETAIL_SQL = 
            "SELECT * FROM " + TABLE_NAME + " WHERE NAME = ?;";

    public static DatabaseHelper getInstance(Context context) {
        if (instance == null && context != null) {
            instance = new DatabaseHelper(context);
        }

        return instance;
    }

    private DatabaseHelper(Context context) {
        super(context, TABLE_NAME, null, DATABASE_VERSION);
    }
    
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_TABLE_SQL);

        ContentValues values = getContentValues(DEFAULT_KEY, 0.0, 0.0, 0.0f,
                VolumeUtil.getCurrentVolume(), VolumeUtil.getCurrentIsVibrate());
        db.insert(TABLE_NAME, null, values);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
        onCreate(db);
    }
    
    public ArrayList<String> getLocationList() {
        Cursor c = null;
        try {
            ArrayList<String> array = new ArrayList<String>();

            c = getReadableDatabase().rawQuery(GET_LOCATIONS_SQL, null);
            while (c.moveToNext()) {
                String name = c.getString(0);
                array.add(name);
            }
            
            return array;
        } finally {
            if (c != null) {
                c.close();
            }
        }
    }
    
    public Location getLocationData(String name) {
        Cursor c = null;
        try {
            Location location;
            
            c = getReadableDatabase().rawQuery(GET_LOCATION_DETAIL_SQL, new String[] {name});
            if (c.moveToFirst()) {
                location = new Location(c);
            } else {
                location = new Location();
            }

            return location;
        } finally {
            if (c != null) {
                c.close();
            }
        }
    }
    
    public void addNewLocation(String name, double longitude, double latitude, float radius,
                               Integer volume, Boolean vibrate) {
        SQLiteDatabase db = null;
        try {
            db = getWritableDatabase();
            ContentValues values = getContentValues(name, longitude, latitude, radius, volume, vibrate);
            db.insert(TABLE_NAME, null, values);
        } finally {
            if (db != null) {
                db.close();
            }
        }
    }
    
    public void addNewLocation(Location location) {
        Map map = location.toMap();
        addNewLocation(
                map.get("name").toString(),
                (Double) map.get("longitude"),
                (Double) map.get("latitude"),
                (Float) map.get("radius"),
                (Integer) map.get("volume"),
                (Boolean) map.get("vibrate"));
    }
    
    public void updateLocation(String key, String name, double longitude, double latitude,
                               float radius, Integer volume, Boolean vibrate) {
        SQLiteDatabase db = null;
        try {
            db = getWritableDatabase();
            ContentValues values = getContentValues(name, longitude, latitude, radius, volume, vibrate);
            db.update(TABLE_NAME, values, "NAME = ?", new String[] {key});
        } finally {
            if (db != null) {
                db.close();
            }
        }
    }

    public void updateLocation(String key, Location location) {
        Map map = location.toMap();
        updateLocation(key,
                map.get("name").toString(),
                (Double) map.get("longitude"),
                (Double) map.get("latitude"),
                (Float) map.get("radius"),
                (Integer) map.get("volume"),
                (Boolean) map.get("vibrate"));
    }

    public void deleteLocation(String location) {
        SQLiteDatabase db = null;
        try {
            db = getWritableDatabase();
            db.delete(TABLE_NAME, "NAME = ?", new String[] {location});
        } finally {
            if (db != null) {
                db.close();
            }
        }
    }

    private ContentValues getContentValues(String name, double longitude, double latitude,
                                           float radius, Integer volume, Boolean vibrate) {
        ContentValues values = new ContentValues();
        values.put("NAME", name);
        values.put("LONGITUDE",
                StringUtil.formatDecimalString(CoordinateUtil.validateLongitude(longitude), 8));
        values.put("LATITUDE",
                StringUtil.formatDecimalString(CoordinateUtil.validateLatitude(latitude), 8));
        values.put("RADIUS", StringUtil.formatDecimalString(radius, 1));
        values.put("VOLUME", volume);
        values.put("VIBRATE", vibrate);
        return values;
    }

    public static List<Map<String, String>> toMapList(Cursor c) {
        List<Map<String, String>> list = new ArrayList<Map<String, String>>();
        if (c.moveToFirst()) {
            do {
                int count = c.getColumnCount();
                Map<String, String> map = new HashMap<String, String>();
                for (int i = 0; i < count; i++) {
                    map.put(c.getColumnName(i), c.getString(i));
                }
                list.add(map);
            } while (c.moveToNext());
        }
        return list;
    }
}
            
